#include "utf8_string.h"


#include <cstring>
#include <assert.h>

#include <algorithm>

/**
 * A few words about the implement.
 *
 * I am sick about the old-style str-function's
 * limitation of the endding \0 and other.
 * And now I use std::search.
 *
 **/

int utf8_string::from_bytes(const char* str) {

    m_chars.clear();

    int len = strlen(str);
    int i = 0;int nbyte = 0;
    int count = 0;
    utf8_char curr_char;

    // We don't need the \0 anymore. so < len
    // just work as we wish.
    while (i < len)
    {
        nbyte = utf8util::leading_byte(str[i]);
        if (nbyte == -1)
            goto bad_input;

        curr_char = UTF8_CHARPAD;
        curr_char.m_part[0] = str[i];
        for (int j = i+1; j < i + nbyte; j++) {
            if (!utf8util::is_continuation_byte(str[j]) || j >= len)
                goto bad_input;
            curr_char.m_part[j-i] = str[j];
        }
        m_chars.push_back(curr_char);

        i += nbyte;
        count++;
    }

    return count;

bad_input:
    m_chars.clear();
    return -1;
}


int utf8_string::length() const {
    return m_chars.size();
}

utf8_char utf8_string::at(unsigned int n) const {
    utf8_char result;
    if (n >= m_chars.size())
        return UTF8_CHARPAD;
    return m_chars[n];
}

utf8_string utf8_string::concat(const utf8_string& str) const {
    utf8_string result;
    result.m_chars = m_chars;
    result.m_chars.insert(result.m_chars.end(),
                          str.m_chars.begin(), str.m_chars.end());
    return result;
}

int utf8_string::find(const utf8_string& pattern) const
{
    using std::vector;
    vector<utf8_char>::const_iterator result;
    result = std::search(m_chars.begin(), m_chars.end(),
                         pattern.m_chars.begin(), pattern.m_chars.end());
    if (result == m_chars.end())
        return -1;
    return std::distance(m_chars.begin(), result);
}

// a out-place implement. It should be a little bit fast than in-place
int utf8_string::replace(const utf8_string& pattern, const utf8_string& to) {
    using std::vector;

    if (pattern.length() == 0)
        return 0;

    int count = 0;
    vector<utf8_char> temp;

    vector<utf8_char>::iterator match;
    vector<utf8_char>::iterator start_point;
    start_point = m_chars.begin();


    while ((match = std::search(start_point, m_chars.end(),
                                    pattern.m_chars.begin(),
                                    pattern.m_chars.end()))
    != m_chars.end())
    {
        count++;
        temp.insert(temp.end(), start_point, match);
        temp.insert(temp.end(),
                    to.m_chars.begin(), to.m_chars.end());
        start_point = match + pattern.m_chars.size();
    }

    // handle the rest
    temp.insert(temp.end(), start_point, m_chars.end());
    // put the result back.
    m_chars = temp;
    return count;
}
